package com.newmainsoftech.dao.entity.relation;

import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;


public class HoldeeListIteratorProxyImpl<E extends HoldeeSide<R>, R extends HolderSide<E>> 
extends HoldeeIteratorProxyImpl<E, R> implements HoldeeListIteratorProxy<E, R> {
	private ListIterator<E> delegateListIterator;
		protected ListIterator<E> getDelegateListIterator() {
			return delegateListIterator;
		}
		protected void setDelegateListIterator( final ListIterator<E> delegateListIterator) {
			this.delegateListIterator = delegateListIterator;
			super.setDelegateIterator( delegateListIterator);
		}
		@Override
		protected Iterator<E> getDelegateIterator() {
			return delegateListIterator;
		}
		
	// Constructors ---------------------------------------------------------------------------
	public HoldeeListIteratorProxyImpl( 
			final R holderEntity, 
			final R defaultHolderEntity, 
			final boolean isOrphanRemovalAttributeOn, 
			final boolean isOkToNullifyHolderAtRemoval, 
			final int listIteratorIndex) {
		super( holderEntity, defaultHolderEntity, isOrphanRemovalAttributeOn, isOkToNullifyHolderAtRemoval);
		
		final Collection<E> holdees = holderEntity.getHoldees();
		if ( !List.class.isInstance( holdees)) {
			throw new IllegalArgumentException(
					MessageFormat.format(
							"Value being returned by {0}.{1} method on {2} " 
							+ "must be a {3} instance but {4}.",
							getGetHoldeesMethod().getDeclaringClass().getSimpleName(),
							getGetHoldeesMethod().getName(),
							holderEntity, 
							List.class.getSimpleName(), 
							holdees)
					);
		}
		
		setDelegateListIterator( ((List<E>)holdees).listIterator( listIteratorIndex));
	}
		
	public HoldeeListIteratorProxyImpl( 
			final R holderEntity, 
			final R defaultHolderEntity, 
			final boolean isOrphanRemovalAttributeOn, 
			final boolean isOkToNullifyHolderAtRemoval) {
		super( holderEntity, defaultHolderEntity, isOrphanRemovalAttributeOn, isOkToNullifyHolderAtRemoval);
		
		final Collection<E> holdees = holderEntity.getHoldees();
			if ( !List.class.isInstance( holdees)) {
				throw new IllegalArgumentException(
						MessageFormat.format(
								"Value being returned by {0}.{1} method on {2} " 
								+ "must be a {3} instance but {4}.",
								getGetHoldeesMethod().getDeclaringClass().getSimpleName(),
								getGetHoldeesMethod().getName(),
								holderEntity, 
								List.class.getSimpleName(), 
								holdees)
						);
			}
		setDelegateListIterator( ((List<E>)holdees).listIterator());
	}
	// ----------------------------------------------------------------------------------------
	
	/**
	 * Being called to handle invocation of <code>add(E e)</code> method of <code>ListIterator</code> 
	 * interface.<br /> 
	 * 
	 * @param proxy
	 * @param method
	 * @param holdee
	 * @return
	 */
	@Override
	public Object interAdd( final Object proxy, final Method method, final E holdee) {
		holdee.ensureIdentity();
			// ensured that business identity of holdee entity has been populated 
			// before adding to collection.
		R holder = getHolderEntity();
		holdee.setHolderEntity( holder);
			// ensured relation from holdee to holder before adding to collection.
		
		getDelegateListIterator().add( holdee);
		return null;
	}
	
	/**
	 * Being called to handle invocation of <code>Set(E e)</code> method of <code>ListIterator</code> 
	 * interface.<br /> 
	 * 
	 * @param proxy
	 * @param method
	 * @param holdee
	 * @return
	 */
	@Override
	public Object interSet( final Object proxy, final Method method, final E holdee) {
		holdee.ensureIdentity();
			// ensured that business identity of holdee entity has been populated 
			// before adding to collection.
		R holder = getHolderEntity();
		holdee.setHolderEntity( holder);
			// ensured relation from holdee to holder before adding to collection.
		
		getDelegateListIterator().set( holdee);
		return null;
	}
	
	@Override
	@SuppressWarnings( value = { "unchecked"})
	public Object invoke( final Object proxy, final Method method, final Object[] args)
	throws Throwable {
		final Class<?>[] parameterTypes = method.getParameterTypes();
		if ( parameterTypes.length == 1) {
			if ( HoldeeSide.class.isInstance( args[ 0])) {
				final E holdee = (E)args[ 0];
				
				final String methodName = method.getName();
				switch( methodName) {
				case "add":
					return interAdd( proxy, method, holdee);
				case "set":
					return interSet( proxy, method, holdee);
				}
			}
		}
		return super.invoke( proxy, method, args);
	}
}